/**
 * Copyright 2008 floop.pl
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 *  
 * http://www.apache.org/licenses/LICENSE-2.0 
 *  
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package org.eaicompiler;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.Properties;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.eaicompiler.antlr.EventAILexer;
import org.eaicompiler.antlr.EventAIParser;
import org.eaicompiler.database.ScriptdevHibernateUtil;
import org.eaicompiler.decompiler.Decompiler;
import org.eaicompiler.model.ScriptDefinition;
import org.eaicompiler.sqlgen.SqlGenerator;
import org.eaicompiler.util.Util;

import com.martiansoftware.jsap.FlaggedOption;
import com.martiansoftware.jsap.JSAP;
import com.martiansoftware.jsap.JSAPException;
import com.martiansoftware.jsap.JSAPResult;
import com.martiansoftware.jsap.Switch;
import com.martiansoftware.jsap.UnflaggedOption;

/**
 * One entry for whole tool. Simplier that way, since we can use one FatJar
 * that'll contain all required libraries to run, and we can run it through java
 * -jar command.
 * 
 * @author floop.pl
 */
public class EAICompilerDecompiler {
	private static final String	PARAM_INPUT	= "input";
	private static final String	PARAM_CREATURE_ID	= "id";
	private static final String	PARAM_OUTPUT	= "output";
	private static final String	PARAM_DECOMPILE	= "decompile";
	private static final String	PARAM_SCRIPT_DEV2_CONFIG_FILE	= "scriptdev2-config";
	private static final String	PARAM_HELP	= "help";
	private static final String	KEY_SCRIPT_DEV2_DATABASE_INFO	= "ScriptDev2DatabaseInfo";	

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws JSAPException, FileNotFoundException, IOException, RecognitionException {
		JSAP jsap = new JSAP();
		jsap.registerParameter(
				new Switch(PARAM_HELP)
				.setShortFlag('?')
				.setLongFlag(PARAM_HELP)
				.setHelp("Print this help file.")
				);
		jsap.registerParameter(
				new FlaggedOption(PARAM_SCRIPT_DEV2_CONFIG_FILE)
				.setShortFlag('s')
				.setLongFlag(PARAM_SCRIPT_DEV2_CONFIG_FILE)
				.setHelp("ScriptDev2 config file location. Used to get the database address/credentials. If not given, the database contacted will be: 127.0.0.1;3306;root;root;scriptdev2")
				);
		jsap.registerParameter(
				new Switch(PARAM_DECOMPILE)
				.setShortFlag('d')
				.setLongFlag(PARAM_DECOMPILE)
				.setHelp("Switch to decompiler. Default is a compiler mode.")
				);
		jsap.registerParameter(
				new FlaggedOption(PARAM_OUTPUT)
				.setStringParser(JSAP.STRING_PARSER)
				.setShortFlag('o')
				.setLongFlag(PARAM_OUTPUT)
				.setHelp("Output file name. If not provided, all output is done to console, which is probably not what you want.")
				);
		jsap.registerParameter(
				new FlaggedOption(PARAM_CREATURE_ID)
		        .setStringParser(JSAP.INTEGER_PARSER)
		        .setRequired(false)
		        .setList(true)
		        .setListSeparator(',')
		        .setShortFlag('i') 
		        .setLongFlag(PARAM_CREATURE_ID)
		        .setHelp("ID (or ID's) of a creature that should be decompiled. If not given, all database will be decompiled.")
		        );		
		jsap.registerParameter(
				new UnflaggedOption(PARAM_INPUT)
				.setHelp("Input file to compile. Required in compile mode.")
				);
        JSAPResult config = jsap.parse(args);
        if (!config.success()) {           
            System.err.println();
            // print out specific error messages describing the problems
            // with the command line, THEN print usage, THEN print full
            // help.  This is called "beating the user with a clue stick."
            for (Iterator errs = config.getErrorMessageIterator();
                    errs.hasNext();) {
                System.err.println("Error: " + errs.next());
            }
            
            System.err.println();
            System.err.println("Usage: java -jar eaicompiler.jar");
            System.err.println("                "
                                + jsap.getUsage());
            System.err.println();
            System.err.println(jsap.getHelp());
            System.exit(1);
        }        
        if(config.getBoolean(PARAM_HELP))
        {
            System.err.println();
            System.err.println("Usage: java -jar eaicompiler.jar");
            System.err.println("                "
                                + jsap.getUsage());
            System.err.println();
            System.err.println(jsap.getHelp());
            System.exit(1);        	
        }
        if(config.getString(PARAM_SCRIPT_DEV2_CONFIG_FILE)!=null)
        {
        	Properties properties = new Properties();
        	properties.load(new FileInputStream(config.getString(PARAM_SCRIPT_DEV2_CONFIG_FILE)));
        	ScriptdevHibernateUtil.setConnectionString(Util.unQuoteString(properties.getProperty(KEY_SCRIPT_DEV2_DATABASE_INFO, "127.0.0.1;3306;root;root;scriptdev2")));
        	System.out.println("Using ScriptDev2 config file: " + config.getString(PARAM_SCRIPT_DEV2_CONFIG_FILE));
        }        
        
		StringBuffer result = new StringBuffer();        
        if(config.getBoolean(PARAM_DECOMPILE))
        {
            StringBuffer selector = new StringBuffer();
            int id[] = config.getIntArray(PARAM_CREATURE_ID);                
            if(id.length>0)
            {
            	selector.append("where creatureId in (");
            	for(int f=0;f<id.length;f++)
            	{
            		selector.append(id[f]);
            		if(f<id.length-1)
            		{
            			selector.append(",");
            		}        			
            	}
            	selector.append(")");
            }        
    		Decompiler d = new Decompiler();
    		result.append(d.decompile(selector.toString()));
        } else {
        	// Compile
        	if(config.getString(PARAM_INPUT)==null)
        	{
        		System.err.println("You have to give the name of an input file to be compiled");
                System.exit(1);        	
       		}
    		CharStream input = new ANTLRFileStream(config.getString(PARAM_INPUT));
    		EventAILexer lex = new EventAILexer(input);
    		CommonTokenStream tokens = new CommonTokenStream(lex);

    		EventAIParser parser = new EventAIParser(tokens);
    		parser.script();

    		StringBuffer localizedTexts = new StringBuffer();
    		StringBuffer events = new StringBuffer();
    		
    		Iterator it = parser.scriptDefinitions.iterator();
    		while(it.hasNext())
    		{
    			ScriptDefinition sd = (ScriptDefinition) it.next();
    			SqlGenerator gen = new SqlGenerator(sd);
    			localizedTexts.append(gen.getLocalizedTextsSQL());
    			events.append(gen.getEventsTextsSQL());
    		}
    		
    		result.append("-- Localized texts:\n");
    		result.append(localizedTexts);
    		result.append("\n");
    		result.append("-- Events :\n");
    		result.append(events);        	
        }
        if(config.getString(PARAM_OUTPUT)!=null)
        {
        	// Decompile
			FileOutputStream out; // declare a file output object
			PrintStream p; // declare a print stream object
			try {
				out = new FileOutputStream(config.getString(PARAM_OUTPUT));
				// Connect print stream to the output stream
				p = new PrintStream(out);
				p.println(result.toString());
				p.close();
				System.out.println("Output written to " + config.getString(PARAM_OUTPUT));
			} catch (Exception e) {
				System.err.println("Error writing to file " + config.getString(PARAM_OUTPUT));
			}			        	
        } else {
        	System.out.println(result.toString());
        }
	}

}
